﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;

namespace Kugar.Core.ExtMethod
{
    public enum FindNodeCheck
    {
        name,
        text,
        both
    }

    public static class TreeViewFunction
    {
        public static string TreeToXml(this TreeNodeCollection tr)
        {
            XmlDocument doc = new XmlDocument();

            doc.LoadXml("<XMLTest></XMLTest>");
            XmlNode root = doc.SelectSingleNode("XMLTest");

            foreach (TreeNode tn in tr)
            {
                XmlElement Test = doc.CreateElement(tn.Name);

                Test.SetAttribute("text", tn.Text);

                root.AppendChild(Test);
                if (tn.Nodes != null && tn.Nodes.Count > 0)
                {
                    ChildNods(tn, Test, doc);
                }
            }

            return doc.InnerXml;
            //doc.Save(s);

            //doc.Save("XMLTest.xml");
        }

        public static bool XmlToTreeView(this TreeNodeCollection tr, string xmlstr)
        {
            if (tr == null || string.IsNullOrEmpty(xmlstr))
            {
                return false;
            }

            tr.Clear();

            var document = new XmlDocument();

            try
            {
                document.LoadXml(xmlstr);
            }
            catch (Exception)
            {
                return false;
            }


            foreach (XmlNode node in document.ChildNodes[0].ChildNodes)
            {
                TreeNode tn = tr.Add(node.Name);

                tn.Text = (node as XmlElement).GetAttribute("text");
                tn.Name = node.Name;


                if (node.ChildNodes != null)
                {
                    ChildNodes(node, tn);
                }
            }

            return true;
        }

        /// <summary>
        ///     按名称搜索节点,返回第一个找到的节点应用
        /// </summary>
        /// <param name="tr"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public static TreeNode FindNode(this TreeView tr, string str)
        {
            return FindNode(tr, str, FindNodeCheck.both);
        }

        /// <summary>
        ///     按选择的选项查找对应的节点
        /// </summary>
        /// <param name="tr">要遍历的树形</param>
        /// <param name="str">匹配字符串</param>
        /// <param name="IsByName">是否按名称搜索,true为按名称搜索,false为按照text属性搜索</param>
        /// <returns></returns>
        public static TreeNode FindNode(this TreeView tr, string str, FindNodeCheck IsByName)
        {
            if (tr == null || tr.Nodes.Count <= 0)
            {
                return null;
            }

            TreeNode ret = null;

            

            foreach (TreeNode node in tr.Nodes)
            {
                switch (IsByName)
                {
                    case FindNodeCheck.both:
                        if (string.Compare(node.Name, str, false) == 0 || string.Compare(node.Text, str, false) == 0)
                        {
                            ret = node;
                            return node;
                        }
                        break;
                    case FindNodeCheck.text:
                        if (string.Compare(node.Text, str, false) == 0)
                        {
                            ret = node;
                            return node;
                        }
                        break;
                    case FindNodeCheck.name:
                        if (string.Compare(node.Name, str, false) == 0)
                        {
                            ret = node;
                            return node;
                        }
                        break;
                }

                CallBackLoop(node, (n1, i) =>
                {
                    var n = (TreeNode)n1;
                    switch (IsByName)
                    {
                        case FindNodeCheck.both:
                            if (string.Compare(n.Name, str, false) == 0 || string.Compare(n.Text, str, false) == 0)
                            {
                                ret = n;
                                return false;
                            }
                            break;
                        case FindNodeCheck.text:
                            if (string.Compare(n.Text, str, false) == 0)
                            {
                                ret = n;
                                return false;
                            }
                            break;
                        case FindNodeCheck.name:
                            if (string.Compare(n.Name, str, false) == 0)
                            {
                                ret = n;
                                return false;
                            }
                            break;
                    }

                    return true;
                });
            }

            return ret;
        }

        /// <summary>
        ///     按选择的选项查找对应的节点
        /// </summary>
        /// <param name="tr">要遍历的树形</param>
        /// <param name="str">匹配字符串</param>
        /// <param name="IsByName">是否按名称搜索,true为按名称搜索,false为按照text属性搜索</param>
        /// <returns></returns>
        public static TreeNode[] FindNode(this TreeView tr, Predicate<TreeNode> checkFunc)
        {
            if (tr == null || tr.Nodes.Count <= 0)
            {
                return null;
            }

            List<TreeNode> lst = new List<TreeNode>(tr.GetNodeCount(true)/2);

            foreach (TreeNode node in tr.Nodes)
            {
                if (checkFunc(node))
                {
                    lst.Add(node);
                }

                CallBackLoop(node, (n1, i) =>
                {
                    var n = (TreeNode)n1;

                    if (checkFunc(n))
                    {
                        lst.Add(n);
                    }
                    return true;
                });
            }

            return lst.ToArray();
        }

        public static bool CopyTreeView(this TreeNodeCollection Src, TreeNodeCollection Des)
        {
            if (Src == null || Des == null || Src.Count <= 0)
            {
                return false;
            }

            var s = TreeToXml(Src);

            return XmlToTreeView(Des, s);
        }

        public static bool CheckIsOnlyByName(this TreeView tr, string namestr)
        {
            bool isonly = true;

            foreach (TreeNode node in tr.Nodes)
            {
                CallBackLoop(node, (n1, i) =>
                {
                    var n = (TreeNode)n1;
                    if (n.Name == namestr)
                    {
                        isonly = false;
                        return false;
                    }

                    return true;
                });
            }

            return isonly;
        }

        public static TreeNode[] GetAllChildNode(this TreeNode tr, bool IsSort)
        {
            if (tr == null)
            {
                return null;
            }

            var lst = new List<TreeNode>(10);

            CallBackLoop(tr, (n1, i) =>
            {
                var n = (TreeNode)n1;
                lst.Add(n);
                return true;
            });

            if (IsSort)
            {
                lst.Sort((n1, n2) =>
                {
                    return string.Compare(n1.Text, n2.Text, true);
                });
            }

            return lst.ToArray();
        }

        public static TreeNode[] GetNodeParentList(this TreeNode tr)
        {
            List<TreeNode> lst = new List<TreeNode>(10);

            CallBackLoopParentOnly(tr, (n1, o) =>
            {
                var n = (TreeNode)n1;
                lst.Add(n);
                return true;
            });

            if (lst.Count <= 0)
            {
                return null;
            }

            return lst.ToArray();
        }

        public static void CallBackLoop(this TreeView tr, ViewNodeCallback call)
        {
            object ttt = null;

            CallBackLoop(tr, call, ttt);
        }

        public static void CallBackLoop(this TreeView tr, ViewNodeCallback call, object state)
        {
            if (tr != null && tr.Nodes.Count <= 0)
            {
                return;
            }

            foreach (TreeNode node in tr.Nodes)
            {
                CallBackLoop(node, call, state);
            }
        }

        public static void CallBackLoop(this TreeNode tr, ViewNodeCallback call)
        {
            object tt = null;
            CallBackLoop(tr, call, tt);
        }

        public static void CallBackLoop(this TreeNode tr, ViewNodeCallback call, object state)
        {
            var temp = new ViewNodeCallEventArgs();
            temp.data = state;
            foreach (TreeNode no in tr.Nodes)
            {

                var ret = call(no, temp);

                if (ret && no != null && no.Nodes.Count > 0)
                {
                    CallBackLoop(no, call, temp.data);
                }
            }
        }

        public static void CallBackLoopParentOnly(this TreeNode tr, ViewNodeCallback call)
        {
            CallBackLoopParentOnly(tr, call, null);
        }

        public static void CallBackLoopParentOnly(this TreeNode tr, TreeViewFunction.ViewNodeCallback call, object state)
        {
            var temp = new ViewNodeCallEventArgs();
            temp.data = state;
            if (tr != null && tr.Parent != null)
            {
                var ret = call(tr.Parent, temp);

                if (ret)
                {
                    CallBackLoopParentOnly(tr.Parent, call, state);
                }

            }

        }

        /// <summary>
        ///     遍历树形控件节点时的回调函数,如果返回值为true,则继续遍历,false则退出遍历
        /// </summary>
        /// <param name="tr">当前节点</param>
        /// <param name="state"></param>
        /// <returns></returns>
        public delegate bool ViewNodeCallback(object tr, ViewNodeCallEventArgs state);

        private static void ChildNods(TreeNode ParentNode, XmlElement Test, XmlDocument doc)
        {
            foreach (TreeNode tn in ParentNode.Nodes)
            {
                XmlElement Ts = doc.CreateElement(tn.Name);

                Ts.SetAttribute("text", tn.Text);

                //Ts.InnerText = tn.Text;

                Test.AppendChild(Ts);

                if (tn.Nodes != null)
                {
                    ChildNods(tn, Ts, doc);
                }
            }
        }

        private static void ChildNodes(XmlNode ParentNode, TreeNode tvNode)
        {
            foreach (XmlNode no in ParentNode.ChildNodes)
            {
                TreeNode tn = tvNode.Nodes.Add(no.Name);

                tn.Text = (no as XmlElement).GetAttribute("text");
                tn.Name = no.Name;

                if (no.ChildNodes != null)
                {
                    ChildNodes(no, tn);
                }
            }
        }

    }

    public class ViewNodeCallEventArgs : EventArgs
    {
        public object data { set; get; }
    }
}
